import asyncio
import logging
import os
import time
from typing import List

from dotenv import load_dotenv
from exchangelib import Credentials, Configuration, Account, DELEGATE, EWSTimeZone
from fastapi_mail import ConnectionConfig, MessageSchema, MessageType, FastMail
from html2text import html2text
from pydantic import BaseModel, EmailStr

import crud
from database import SessionLocal
from models import Role
from schemas import ReqCreate

load_dotenv()

# Global constants
IMAP_SERVER = os.environ['IMAP_SERVER']
SMTP_SERVER = os.environ['SMTP_SERVER']
IMAP_PORT = int(os.environ['IMAP_PORT'])
SMTP_PORT = int(os.environ['SMTP_PORT'])
MAIL_USERNAME = os.environ['FORM_SERVICE_MAIL']
MAIL_PASSWORD = os.environ['FORM_SERVICE_MAIL_PASSWORD']

conf = ConnectionConfig(
    MAIL_USERNAME=MAIL_USERNAME,
    MAIL_PASSWORD=MAIL_PASSWORD,
    MAIL_FROM=MAIL_USERNAME,
    MAIL_PORT=SMTP_PORT,
    MAIL_SERVER=SMTP_SERVER,
    MAIL_STARTTLS=False,
    MAIL_SSL_TLS=False,
    USE_CREDENTIALS=False,
    VALIDATE_CERTS=True
)


class EmailSchema(BaseModel):
    email: List[EmailStr]


credentials = Credentials(username=MAIL_USERNAME, password=MAIL_PASSWORD)
config = Configuration(server=IMAP_SERVER, credentials=credentials)
account = Account(
    primary_smtp_address=MAIL_USERNAME,
    config=config,
    autodiscover=False,
    access_type=DELEGATE,
    default_timezone=EWSTimeZone('Asia/Sakhalin')
)


async def send_to(
        email: str, subject: str, body: str
) -> None:
    recipients = EmailSchema(email=[email])
    message = MessageSchema(
        subject=subject,
        recipients=recipients.email,
        body=body,
        subtype=MessageType.html
    )

    fm = FastMail(conf)
    await fm.send_message(message)


# async def reply_to(
#         email: str, subject: str, body: str
# ) -> None:
#     recipients = EmailSchema(email=[email])
#     message = MessageSchema(
#         recipients=recipients.email,
#         subject=subject,
#         reply_to=recipients.email,
#         body=body,
#         subtype=MessageType.html
#     )
#
#     fm = FastMail(conf)
#     await fm.send_message(message)


async def read_inbox():
    inbox = account.inbox

    with SessionLocal() as session:
        for message in inbox.filter(is_read=False):
            user_email = message.author.email_address
            user = crud.get_user_by_email(session, user_email)
            if user is None:
                await send_to(user_email, 'Чтобы оставлять заявки через почту надо зарегистрироваться',
                              "Вы можете зарегистрироваться на сайте")
                message.is_read = True
                message.save()
                continue
            if user.role != Role.User:
                await send_to(user_email, 'Превышение полномочий: Только пользователи могут отправлять заявки',
                              'Вы можете создать себе аккаунт с ролью пользователь на сайте')
                message.is_read = True
                message.save()
                continue
            topic = message.subject
            if message.body.body_type == 'HTML':
                md_description = html2text(message.body)
            else:
                md_description = message.body

            req_create = ReqCreate(topic=topic, description=md_description)
            crud.create_req(session, req_create, user.id)
            await send_to(user_email, 'Заявка принята',
                          "Вам прийдет ответное письмо, когда ваш запрос будет обработан")
            message.is_read = True
            message.save()


async def main():
    while True:
        try:
            await read_inbox()
        except ConnectionError as e:
            logging.exception("Error connecting to inbox: %s", e)
        except Exception as e:
            logging.exception("Unexpected error: %s", e)

        await asyncio.sleep(5)


if __name__ == "__main__":
    # Configure logging
    logging.basicConfig(level=logging.INFO)
    asyncio.run(main())
